import os
import random

import pyJianYingDraft as draft
from pyJianYingDraft import Shrink_mode, Extend_mode, Crop_settings, trange, Intro_type, Clip_settings
from pyJianYingDraft.template_mode import Imported_media_track
from .config import DRAFT_PATH, TEMPLATE_NAME, \
    REMOVE_DUPLICATE_TRACK_MATERIAL_DIR, ENABLE_RANDOM_ANIMATION_VIDEO_MATERIAL
from combinations.conf import logger
from .utils import _update_segment_with_new_animation_and_speed

import cv2


def get_video_duration(video_path):
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        raise ValueError("无法打开视频文件")

    fps = cap.get(cv2.CAP_PROP_FPS)
    total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
    duration = total_frames / fps

    cap.release()

    return min(duration, 10)  # 取视频时长和10秒的较小值


from moviepy import AudioFileClip


def get_audio_duration(audio_path):
    try:
        with AudioFileClip(audio_path) as audio:
            duration_seconds = audio.duration  # 获取音频时长（秒）
        return min(duration_seconds, 10)  # 最多取10秒
    except Exception as e:
        raise ValueError(f"无法读取音频文件: {audio_path}，错误: {str(e)}")


class DraftHandler:
    def __init__(self):
        self.draft_folder = draft.Draft_folder(DRAFT_PATH)
        # logger.info("草稿处理器初始化成功")

    def create_draft(self, combo_name: str, combinations: tuple, material_mapping: dict, kou_tu=False,
                     ):
        """创建新的草稿并替换素材"""
        try:
            logger.info(f"****开始创建视频: {combo_name}")
            try:
                script = self.draft_folder.duplicate_as_template(TEMPLATE_NAME, combo_name,
                                                                 allow_replace=True, kou_tu=kou_tu)
            except Exception as e:
                logger.error(f"创建草稿失败: {e}")
                raise e
            print(1)
            for original_material, new_material_info in material_mapping.items():
                # 根据 material_mapping 的 value 确定 combo 中的索引 value 肯定是唯一的

                material_replace_status = {}
                for item in combinations:
                    # 读取素材替换状态，如果已经替换过，则跳过
                    if item in material_replace_status and material_replace_status[item]:
                        continue
                    if "text-track" in original_material:
                        if new_material_info[0] in item.split("/")[0]:
                            # 这段是去除前面加的素材文件夹标识
                            new_material = item.replace(new_material_info[0] + '/', '')
                            logger.info(
                                f"开始:替换【文本】素材: {original_material} -> 文件夹{new_material_info[0]}里的内容{new_material}")

                            # logger.info(f"开始:替换【文本】素材: {original_material} -> {new_material}")
                            # 替换文本的判断
                            # 文本的key结构 text-track_{text_track_index}_{segment_index}
                            # 中文说明： text_track_{轨道下标}_{片段下标}
                            params = original_material.split("_")
                            text_track_index = int(params[1])
                            segment_index = int(params[2])
                            logger.info(
                                f"开始将【文本】轨道: {text_track_index}，第 {segment_index}段文本，替换为：{new_material}")
                            text_track = script.get_imported_track(
                                draft.Track_type.text,  # 选取导入的音频轨道
                                index=text_track_index  # 也可用下标定位, 0表示最底层的同类型轨道
                            )
                            text = new_material
                            script.replace_text(
                                text_track, segment_index,  # 选取text_track中下标为0的片段，也即第一个片段
                                text=text  # 新的文本内容
                            )
                    elif "sticker-segment" in original_material:
                        if new_material_info[0] in os.path.dirname(item):
                            new_material = item
                            logger.info(f"开始:替换【贴纸】素材: {original_material} -> {new_material}")
                            # 贴纸的 key 结构 sticker-segment_{text_track_index}_{segment_index}
                            # 贴纸替换
                            params = original_material.split("_")
                            # resource_id = params[1]
                            track_index = int(params[1])
                            segment_index = int(params[2])
                            logger.info(
                                f"开始将【贴纸】轨道: {track_index}，第 {segment_index}段文本，替换为：{new_material}")
                            new_material = draft.Video_material(new_material)

                            video_track = script.get_imported_track(
                                draft.Track_type.video,  # 选取导入的音频轨道
                                # 轨道index
                                index=track_index  # 也可用下标定位, 0表示最底层的同类型轨道
                            )
                            script.replace_material_by_seg(
                                # 轨道
                                video_track,
                                # 片段index
                                segment_index=segment_index,
                                material=new_material,
                                # 选取audio_track中下标为0的片段，也即第一个片段
                                source_timerange=None,  # 若不指定，则默认使用整个素材
                                # source_timerange=trange("0s", "10s"),  # 此处指定截取素材前10秒(注意原片段时长为5秒)
                                handle_shrink=Shrink_mode.cut_tail,  # 片段若要缩短，则依靠前移终止点来实现
                                handle_extend=Extend_mode.push_tail  # 片段若要延长，则依靠后移终止点来实现，必要时允许后移后续片段
                            )
                    elif new_material_info[0] in os.path.dirname(item):
                        new_material = item
                        # 替换 视频、音频
                        if original_material.split(".")[-1].lower() in ("mp3", "wav"):
                            logger.info(f"开始:替换【音频】素材: {original_material} -> {new_material}")
                            try:
                                new_material = draft.Audio_material(new_material)
                                script.replace_material_by_name(material_name=original_material, material=new_material)
                            except Exception as e:
                                logger.error(f"{str(e)}")
                                logger.error(f"替换音频失败,下一个")
                                continue
                        else:
                            # 视频(JPG、PNG、MP4)
                            logger.info(f"开始:替换【视频】素材: {original_material} -> {new_material}")
                            try:
                                new_material = draft.Video_material(new_material)
                                # #自定义脚本，增加新的轨道，覆盖其上，增加动画
                                # #去重轨道
                                if ENABLE_RANDOM_ANIMATION_VIDEO_MATERIAL is True:
                                    logger.info(f"增加随机入场动画")

                                    if "封面" not in original_material.lower():
                                        script, material_id = script.replace_material_by_name(
                                            material_name=original_material,
                                            material=new_material)

                                        # 遍历所有导入轨道，查找对应 segment 并更新动画/速度等信息
                                        for track in script.imported_tracks:
                                            if not isinstance(track, Imported_media_track):
                                                continue  # 跳过非媒体轨道

                                            if not isinstance(track.segments, list):
                                                continue  # 跳过没有 segments 的轨道

                                            for segment in track.segments:
                                                if isinstance(segment, dict):  # 跳过字典类型
                                                    continue

                                                # 如果找到匹配的素材 ID
                                                if segment.material_id == material_id:
                                                    _update_segment_with_new_animation_and_speed(
                                                        script=script,
                                                        segment=segment,
                                                        new_material=new_material,
                                                        speed_factor=0.8)
                                        script = script
                                else:
                                    logger.info(f"不增加随机入场动画")

                                    script.replace_material_by_name(material_name=original_material,
                                                                    material=new_material)
                            except Exception as e:
                                logger.error(f"{str(e)}")
                                logger.error(f"替换视频失败 ,下一个")
                                continue
                    # 记录素材替换状态
                    material_replace_status[item] = True

            if REMOVE_DUPLICATE_TRACK_MATERIAL_DIR != "":
                if os.path.exists(REMOVE_DUPLICATE_TRACK_MATERIAL_DIR):
                    video_file_path = select_random_media_file(
                        os.path.join(REMOVE_DUPLICATE_TRACK_MATERIAL_DIR, 'video'), media_type="video")
                    logger.info(f"开始：新增【无意义透明去重】轨道")
                    logger.info(f"无意义视频素材地址:{video_file_path}")
                    video_mat = draft.Video_material(video_file_path)
                    script.add_track(draft.Track_type.video, relative_index=99, track_name="无意义视频去重轨道")
                    video_duration = get_video_duration(video_file_path)
                    video_seg = draft.Video_segment(video_mat, trange("0s", f"{video_duration}s"), volume=0,
                                                    clip_settings=Clip_settings(alpha=0.01))
                    script.add_segment(video_seg, track_name="无意义视频去重轨道")

                    audio_file_path = select_random_media_file(
                        os.path.join(REMOVE_DUPLICATE_TRACK_MATERIAL_DIR, 'audio'), media_type="audio")
                    logger.info(f"无意义音频素材地址:{audio_file_path}")
                    audio_mat = draft.Audio_material(audio_file_path)
                    audio_duration = get_audio_duration(audio_file_path)
                    script.add_track(draft.Track_type.audio, relative_index=98, track_name="无意义音频去重轨道")
                    audio_seg = draft.Audio_segment(audio_mat, trange("0s", f"{audio_duration}s"), volume=0.1)
                    script.add_segment(audio_seg, track_name="无意义音频去重轨道")
                else:
                    logger.error(f"透明轨道素材去重目录 {REMOVE_DUPLICATE_TRACK_MATERIAL_DIR} 不存在")
            logger.info(f"****视频 {combo_name} 组合部分保存成功")
            return script
        except Exception as e:
            logger.error(f"创建视频 {combo_name} 组合部分失败: {str(e)}")


def select_random_media_file(directory, media_type="video"):
    """
    扫描指定目录下的视频或音频文件，并随机选择一个文件路径。

    :param directory: 要扫描的目录路径
    :param media_type: 媒体类型，"video" 表示视频文件，"audio" 表示音频文件
    :return: 随机选中的媒体文件路径，如果没有找到则返回 None
    """
    try:
        # 定义视频和音频文件的常见后缀
        video_extensions = (".mp4", ".avi", ".mkv", ".mov", ".flv")
        audio_extensions = (".mp3", ".wav", ".ogg", ".aac", ".flac")

        # 根据媒体类型选择对应的文件后缀
        if media_type == "video":
            extensions = video_extensions
        elif media_type == "audio":
            extensions = audio_extensions
        else:
            logger.error(f"不支持的媒体类型: {media_type}")
            return None

        # 获取目录下所有符合条件的文件
        media_files = [os.path.join(root, file) for root, dirs, files in os.walk(directory) for file in files
                       if file.lower().endswith(extensions)]

        if not media_files:
            logger.warning(f"在目录 {directory} 中未找到 {media_type} 文件")
            return None

        # 随机选取一个文件
        selected_file = random.choice(media_files)
        logger.info(f"随机选中的 {media_type} 文件: {selected_file}")
        return selected_file
    except Exception as e:
        logger.error(f"扫描目录 {directory} 或选择文件时发生错误: {str(e)}")
        return None
